#include <iostream>
#include <thread>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <cstdio>

using namespace std;

// struct ThreadData
// {
// public:
//     ThreadData(const string n,pthread_mutex_t *pm)
//         :tname(n)
//         ,pmtx(pm)
//     {}
// public:
//     string tname;
//     pthread_mutex_t *pmtx;
// };
// // 如果多线程访问同一个全局变量，并对它进行数据计算，多线程会互相影响吗？
// //pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;//全局的锁
// int tickets = 10000; // 在并发访问的时候，导致了我们数据不一致的问题！

// void *getTickets(void *args)
// {
//     ThreadData *td = (ThreadData*)args;
//     while(true)
//     {
//         pthread_mutex_lock(td->pmtx);//加锁
//         if(tickets > 0)
//         {
//             usleep(1000);
//             printf("%s: %d\n", td->tname.c_str(), tickets);
//             tickets--;
//             pthread_mutex_unlock(td->pmtx);//解锁
//         } 
//         else{
//             pthread_mutex_unlock(td->pmtx);//解锁
//             break;
//         }
//     }
//     delete td;
//     return nullptr;
// }

// #define THREAD_NUM 5


// int main()
// {
//     pthread_mutex_t mtx;//定义局部锁
//     pthread_mutex_init(&mtx,nullptr);//初始化锁
//     //pthread_t t1,t2,t3;
//     pthread_t t[THREAD_NUM];
//     // 多线程抢票的逻辑

//     for(int i = 0;i<THREAD_NUM;i++)
//     {
//         string name = "thread";
//         name+=to_string(i+1);
//         ThreadData *td = new ThreadData(name,&mtx);
//         pthread_create(t + i,nullptr,getTickets,(void*)td);
//     }
//     for(int i = 0;i<THREAD_NUM;i++)
//     {
//         pthread_join(t[i],nullptr);
//     }

//     pthread_mutex_destroy(&mtx);//释放锁

//     // pthread_create(&t1, nullptr, getTickets,(void*)"thread one");
//     // pthread_create(&t2, nullptr, getTickets,(void*)"thread two");
//     // pthread_create(&t3, nullptr, getTickets,(void*)"thread three");

//     // pthread_join(t1, nullptr);
//     // pthread_join(t2, nullptr);
//     // pthread_join(t3, nullptr);

//     return 0;
// }


#define TNUM 4
typedef void (*func_t)(const std::string &name,pthread_mutex_t *pmtx, pthread_cond_t *pcond);
volatile bool quit = false;

// pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

class ThreadData
{
public:
    ThreadData(const std::string &name, func_t func, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
    :name_(name), func_(func), pmtx_(pmtx), pcond_(pcond)
    {}
public:
    std::string name_;
    func_t func_;
    pthread_mutex_t *pmtx_;
    pthread_cond_t *pcond_;
};

void func1(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        // wait一定要在加锁和解锁之间进行wait！
        // v2: 
        pthread_mutex_lock(pmtx);
        // if(临界资源是否就绪-- 否) pthread_cond_wait
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running -- 播放" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func2(const std::string &name,pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        if(!quit) std::cout << name << " running  -- 下载" << std::endl;
        pthread_mutex_unlock(pmtx);

    }
}
void func3(const std::string &name,pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running  -- 刷新" << std::endl;
        pthread_mutex_unlock(pmtx);

    }
}
void func4(const std::string &name,pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx); //默认该线程在执行的时候，wait代码被执行，当前线程会被立即被阻塞
        std::cout << name << " running  -- 扫描用户信息" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void *Entry(void *args)
{
    ThreadData *td = (ThreadData*)args; //td在每一个线程自己私有的栈空间中保存
    td->func_(td->name_, td->pmtx_, td->pcond_); // 它是一个函数，调用完成就要返回！
    delete td;
    return nullptr;
}

int main()
{
    pthread_mutex_t mtx;//定义锁
    pthread_cond_t cond;//定义条件变量
    pthread_mutex_init(&mtx, nullptr);//初始化
    pthread_cond_init(&cond, nullptr);//初始化

    pthread_t tids[TNUM];
    func_t funcs[TNUM] = {func1, func2, func3, func4};
    for (int i = 0; i < TNUM; i++)
    {
        std::string name = "Thread ";
        name += std::to_string(i+1);
        ThreadData *td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create(tids + i, nullptr, Entry, (void*)td);
    }

    sleep(5);

    // ctrl new thread
    int cnt = 10;
    while(cnt)
    {
        std::cout << "resume thread run code ...." << cnt-- << std::endl;
        //pthread_cond_signal(&cond);//唤醒指定线程
        pthread_cond_broadcast(&cond);//唤醒全部线程
        sleep(1);
    }

    std::cout << "ctrl done" << std::endl;
    quit = true;
    pthread_cond_broadcast(&cond);//检测

    for(int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread: " << tids[i] << "quit" << std::endl;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}